package com.skyyan.netty.jjf.protocol;

import cn.hutool.core.util.ByteUtil;

import java.util.Arrays;

/**
 * C.8 阶梯水电价查询
 * AFN = 0x99
 *
 * 上行报文格式（设备 → 中心）：
 * 起始字符0x68
 * 长度1个字节
 * 起始字符0x68
 * - 控制域：0x01
 * - 地址域：19字节（设备注册号16 + 管理机号3）
 * - 地址域[1]-[16] 设备注册号 16进制 低位在前 高位在后
 * - 地址域[17]-[19] 手持终端设备序列号  3字节 低位在前 高位在后
 * - AFN：0x99
 *   CRC
 * - 结束字符0x16
 *
 * 下行报文格式（中心 → 设备）：
 * 起始字符0x68
 * 长度1个字节
 * 起始字符0x68
 * - 控制域：0x00
 * - AFN 0x99
 * - 数据域：19字节
 * - 状态 数据域[1] 状态码BCD码
 * - 数据域[2]-[4] 一阶水价  16进制 高位在前 低位在后
 * - 数据域[5]-[7] 二阶水价  16进制 高位在前 低位在后 3位小数
 * - 数据域[8]-[10] 三阶水价  16进制 高位在前 低位在后 3位小数
 * - 数据域[11]-[13] 一阶电费  16进制 高位在前 低位在后 3位小数
 * - 数据域[14]-[16] 二阶电费  16进制 高位在前 低位在后 3位小数
 * - 数据域[17]-[19] 三阶电费  16进制 高位在前 低位在后 3位小数
 *   CRC
 * - 结束字符0x16
 *
 * @author skyyan
 */
public class WaterElectricityPriceQueryMessage extends Message {

    /**
     * 构造函数，供MessageFactory使用
     * @param control 控制域
     * @param address 地址域
     * @param afn AFN
     * @param userData 用户数据
     */
    public WaterElectricityPriceQueryMessage(byte control, byte[] address, byte afn, byte[] userData) {
        super(control, address, afn, userData);
    }

    /**
     * 创建19字节地址域
     * @param deviceRegIdBytes 设备注册号 (16字节)
     * @param deviceSerialNoBytes 手持终端设备序列号 (3字节)
     * @return 19字节地址域
     */
    private static byte[] createAddress(byte[] deviceRegIdBytes, byte[] deviceSerialNoBytes) {
        byte[] address = new byte[19];

        // 设备注册号 (16字节)
        if (deviceRegIdBytes != null) {
            System.arraycopy(deviceRegIdBytes, 0, address, 0, Math.min(deviceRegIdBytes.length, 16));
        }

        // 手持终端设备序列号 (3字节)
        if (deviceSerialNoBytes != null) {
            System.arraycopy(deviceSerialNoBytes, 0, address, 16, Math.min(deviceSerialNoBytes.length, 3));
        }

        return address;
    }

    /**
     * 创建19字节地址域 (使用int类型的设备序列号)
     * @param deviceRegIdBytes 设备注册号 (16字节)
     * @param deviceSerialNo 手持终端设备序列号 (int类型)
     * @return 19字节地址域
     */
    private static byte[] createAddress(byte[] deviceRegIdBytes, int deviceSerialNo) {
        byte[] address = new byte[19];

        // 设备注册号 (16字节)
        if (deviceRegIdBytes != null) {
            System.arraycopy(deviceRegIdBytes, 0, address, 0, Math.min(deviceRegIdBytes.length, 16));
        }

        // 手持终端设备序列号 (3字节，低位在前)
        address[16] = (byte) (deviceSerialNo & 0xFF);
        address[17] = (byte) ((deviceSerialNo >> 8) & 0xFF);
        address[18] = (byte) ((deviceSerialNo >> 16) & 0xFF);

        return address;
    }

    /**
     * 上行报文 (设备 → 中心)
     */
    public static class Uplink extends WaterElectricityPriceQueryMessage {

        public Uplink(byte[] address) {
            super(FrameConstants.CONTROL_UPLINK,
                    address,
                    FrameConstants.AFN_WATER_ELECTRICITY_PRICE_QUERY,
                    null); // 用户数据为空表示是价格查询报文
        }

        /**
         * 构造一个上行的查询储水价、电价报文
         * @param deviceRegIdBytes 设备注册号 (16字节) 低位在前 高位在后
         * @param deviceSerialNo 手持终端设备序列号 (int类型) 低位在前 高位在后
         */
        public Uplink(byte[] deviceRegIdBytes, int deviceSerialNo) {
            super(FrameConstants.CONTROL_UPLINK,
                  createAddress(deviceRegIdBytes, deviceSerialNo),
                  FrameConstants.AFN_WATER_ELECTRICITY_PRICE_QUERY,
                  null); // 用户数据为空表示是价格查询报文
        }

        /**
         * 从地址域中提取设备注册号
         * @return 设备注册号 (16字节) 低位在前 高位在后
         */
        public byte[] getDeviceRegIdBytes() {
            byte[] address = getAddress();
            if (address == null || address.length < 16) {
                return new byte[16];
            }
            byte[] deviceId = new byte[16];
            System.arraycopy(address, 0, deviceId, 0, 16);
            return deviceId;
        }

        /**
         * 从地址域中提取手持终端设备序列号
         * @return 手持终端设备序列号 (3字节) 低位在前 高位在后
         */
        public byte[] getDeviceSerialNoBytes() {
            byte[] address = getAddress();
            if (address == null || address.length < 19) {
                return new byte[3];
            }
            byte[] serialNo = new byte[3];
            System.arraycopy(address, 16, serialNo, 0, 3);
            return serialNo;
        }

        /**
         * 获取手持终端设备序列号 (int类型)
         * @return 手持终端设备序列号
         */
        public int getDeviceSerialNoInt() {
            byte[] deviceSerialNoBytes = getDeviceSerialNoBytes();
            if (deviceSerialNoBytes != null && deviceSerialNoBytes.length >= 3) {
                return (deviceSerialNoBytes[0] & 0xFF) |
                       ((deviceSerialNoBytes[1] & 0xFF) << 8) |
                       ((deviceSerialNoBytes[2] & 0xFF) << 16);
            }
            return 0;
        }

        @Override
        public String toString() {
            return "WaterElectricityPriceQueryMessage.Uplink{" +
                    "control=0x" + String.format("%02X", getControl()) +
                    ", afn=0x" + String.format("%02X", getAfn()) +
                    ", deviceRegIdBytes=" + bytesToHex(getDeviceRegIdBytes()) +
                    ", deviceSerialNoBytes=" + bytesToHex(getDeviceSerialNoBytes()) +
                    ", deviceSerialNoInt=0x" + String.format("%06X", getDeviceSerialNoInt()) +
                    '}';
        }
    }

    /**
     * 下行报文 (中心 → 设备)
     */
    public static class Downlink extends WaterElectricityPriceQueryMessage {

        private byte statusCodeBCD;
        private byte[] waterPrice1;   // 1阶水价
        private byte[] waterPrice2;   // 2阶水价
        private byte[] waterPrice3;   // 3阶水价
        private byte[] tieredPrice1;  // 1阶电价
        private byte[] tieredPrice2;  // 2阶电价
        private byte[] tieredPrice3;  // 3阶电价

        public void setStatusCodeBCD(byte statusCodeBCD) {
            this.statusCodeBCD = statusCodeBCD;
        }

        public void setWaterPrice1(byte[] waterPrice1) {
            this.waterPrice1 = waterPrice1;
        }

        public void setWaterPrice2(byte[] waterPrice2) {
            this.waterPrice2 = waterPrice2;
        }

        public void setWaterPrice3(byte[] waterPrice3) {
            this.waterPrice3 = waterPrice3;
        }

        public void setTieredPrice1(byte[] tieredPrice1) {
            this.tieredPrice1 = tieredPrice1;
        }

        public void setTieredPrice2(byte[] tieredPrice2) {
            this.tieredPrice2 = tieredPrice2;
        }

        public void setTieredPrice3(byte[] tieredPrice3) {
            this.tieredPrice3 = tieredPrice3;
        }

        /**
         * 构造一个下行的价格查询响应报文
         * @param statusCodeBCD 状态码BCD
         * @param waterPrice1 1阶水价 (3字节)
         * @param waterPrice2 2阶水价 (3字节)
         * @param waterPrice3 3阶水价 (3字节)
         * @param tieredPrice1 1阶电价 (3字节)
         * @param tieredPrice2 2阶电价 (3字节)
         * @param tieredPrice3 3阶电价 (3字节)
         */
        public Downlink(
                       byte statusCodeBCD,
                       byte[] waterPrice1, byte[] waterPrice2, byte[] waterPrice3,
                       byte[] tieredPrice1, byte[] tieredPrice2, byte[] tieredPrice3) {
            super(FrameConstants.CONTROL_DOWNLINK,
                   null,
                  FrameConstants.AFN_WATER_ELECTRICITY_PRICE_QUERY,
                  createUserData(statusCodeBCD, waterPrice1, waterPrice2, waterPrice3,
                               tieredPrice1, tieredPrice2, tieredPrice3));

            this.statusCodeBCD = statusCodeBCD;
            this.waterPrice1 = copyBytes(waterPrice1, 3);
            this.waterPrice2 = copyBytes(waterPrice2, 3);
            this.waterPrice3 = copyBytes(waterPrice3, 3);
            this.tieredPrice1 = copyBytes(tieredPrice1, 3);
            this.tieredPrice2 = copyBytes(tieredPrice2, 3);
            this.tieredPrice3 = copyBytes(tieredPrice3, 3);
        }



        /**
         * 供解码器使用的构造函数
         * @param control 控制域
         * @param address 地址域
         * @param userData 用户数据
         */
        public Downlink(byte control, byte[] address, byte[] userData) {
            super(control, address, FrameConstants.AFN_WATER_ELECTRICITY_PRICE_QUERY, userData);

            // 解析用户数据
            if (userData != null && userData.length >= 19) {
                this.statusCodeBCD = userData[0];

                // 解析各价格字段
                this.waterPrice1 = Arrays.copyOfRange(userData, 1, 4);
                this.waterPrice2 = Arrays.copyOfRange(userData, 4, 7);
                this.waterPrice3 = Arrays.copyOfRange(userData, 7, 10);
                this.tieredPrice1 = Arrays.copyOfRange(userData, 10, 13);
                this.tieredPrice2 = Arrays.copyOfRange(userData, 13, 16);
                this.tieredPrice3 = Arrays.copyOfRange(userData, 16, 19);
            } else {
                // 设置默认值
                this.statusCodeBCD = 0x00;
                this.waterPrice1 = new byte[3];
                this.waterPrice2 = new byte[3];
                this.waterPrice3 = new byte[3];
                this.tieredPrice1 = new byte[3];
                this.tieredPrice2 = new byte[3];
                this.tieredPrice3 = new byte[3];
            }
        }

        /**
         * 从地址域中提取设备注册号
         * @return 设备注册号 (16字节)
         */
        public byte[] getDeviceRegIdBytes() {
            byte[] address = getAddress();
            if (address == null || address.length < 16) {
                return new byte[16];
            }
            byte[] deviceId = new byte[16];
            System.arraycopy(address, 0, deviceId, 0, 16);
            return deviceId;
        }

        /**
         * 从地址域中提取手持终端设备序列号
         * @return 手持终端设备序列号 (3字节)
         */
        public byte[] getDeviceSerialNoBytes() {
            byte[] address = getAddress();
            if (address == null || address.length < 19) {
                return new byte[3];
            }
            byte[] serialNo = new byte[3];
            System.arraycopy(address, 16, serialNo, 0, 3);
            return serialNo;
        }

        /**
         * 创建用户数据
         */
        private static byte[] createUserData(byte statusCodeBCD,
                                           byte[] waterPrice1, byte[] waterPrice2, byte[] waterPrice3,
                                           byte[] tieredPrice1, byte[] tieredPrice2, byte[] tieredPrice3) {
            byte[] userData = new byte[19];
            userData[0] = statusCodeBCD;

            // 填充各价格字段
            System.arraycopy(copyBytes(waterPrice1, 3), 0, userData, 1, 3);
            System.arraycopy(copyBytes(waterPrice2, 3), 0, userData, 4, 3);
            System.arraycopy(copyBytes(waterPrice3, 3), 0, userData, 7, 3);
            System.arraycopy(copyBytes(tieredPrice1, 3), 0, userData, 10, 3);
            System.arraycopy(copyBytes(tieredPrice2, 3), 0, userData, 13, 3);
            System.arraycopy(copyBytes(tieredPrice3, 3), 0, userData, 16, 3);

            return userData;
        }

        /**
         * 复制字节数组，确保长度正确
         */
        private static byte[] copyBytes(byte[] src, int length) {
            if (src == null) {
                return new byte[length];
            }

            byte[] dest = new byte[length];
            System.arraycopy(src, 0, dest, 0, Math.min(src.length, length));
            return dest;
        }

        public byte getStatusCodeBCD() {
            return statusCodeBCD;
        }

        public byte[] getWaterPrice1() {
            return waterPrice1 != null ? waterPrice1.clone() : new byte[3];
        }

        public byte[] getWaterPrice2() {
            return waterPrice2 != null ? waterPrice2.clone() : new byte[3];
        }

        public byte[] getWaterPrice3() {
            return waterPrice3 != null ? waterPrice3.clone() : new byte[3];
        }

        public byte[] getTieredPrice1() {
            return tieredPrice1 != null ? tieredPrice1.clone() : new byte[3];
        }

        public byte[] getTieredPrice2() {
            return tieredPrice2 != null ? tieredPrice2.clone() : new byte[3];
        }

        public byte[] getTieredPrice3() {
            return tieredPrice3 != null ? tieredPrice3.clone() : new byte[3];
        }

        /**
         * 将3字节价格转换为int值（单位：厘，保留3位小数）
         * @param priceBytes 3字节价格数据（高位在前）
         * @return 价格值（单位：厘）
         */
        public int getPriceValue(byte[] priceBytes) {
//            if (priceBytes == null || priceBytes.length != 3) {
//                return 0;
//            }
//            // 高位在前，需要转换为大端序
//            byte[] bigEndianBytes = new byte[4];
//            bigEndianBytes[0] = 0; // 符号位
//            bigEndianBytes[1] = priceBytes[0]; // 高位
//            bigEndianBytes[2] = priceBytes[1];
//            bigEndianBytes[3] = priceBytes[2]; // 低位
//            return ByteUtil.bytesToInt(bigEndianBytes);
            if (priceBytes == null || priceBytes.length != 3) {
                return 0;
            }
            // 高位在前，按大端序解析
            return ((priceBytes[0] & 0xFF) << 16) |
                    ((priceBytes[1] & 0xFF) << 8)  |
                    (priceBytes[2] & 0xFF);
        }

        /**
         * 获取1阶水价（单位：厘）
         */
        public int getWaterPrice1Value() {
            return getPriceValue(getWaterPrice1());
        }

        /**
         * 获取2阶水价（单位：厘）
         */
        public int getWaterPrice2Value() {
            return getPriceValue(getWaterPrice2());
        }

        /**
         * 获取3阶水价（单位：厘）
         */
        public int getWaterPrice3Value() {
            return getPriceValue(getWaterPrice3());
        }

        /**
         * 获取1阶电价（单位：厘）
         */
        public int getTieredPrice1Value() {
            return getPriceValue(getTieredPrice1());
        }

        /**
         * 获取2阶电价（单位：厘）
         */
        public int getTieredPrice2Value() {
            return getPriceValue(getTieredPrice2());
        }

        /**
         * 获取3阶电价（单位：厘）
         */
        public int getTieredPrice3Value() {
            return getPriceValue(getTieredPrice3());
        }

        /**
         * 从地址域中提取设备注册号
         * @return 设备注册号 (16字节)
         */
        public byte[] getDeviceRegistrationId() {
            byte[] address = getAddress();
            if (address == null || address.length < 16) {
                return new byte[16];
            }
            byte[] deviceId = new byte[16];
            System.arraycopy(address, 0, deviceId, 0, 16);
            return deviceId;
        }

        /**
         * 从地址域中提取充值管理机序号
         * @return 充值管理机序号 (4字节)
         */
        public byte[] getRechargeManagerId() {
            byte[] address = getAddress();
            if (address == null || address.length < 20) {
                return new byte[4];
            }
            byte[] managerId = new byte[4];
            System.arraycopy(address, 16, managerId, 0, 4);
            return managerId;
        }

        @Override
        public String toString() {
            return "WaterElectricityPriceQueryMessage.Downlink{" +
                    "address=" + (getAddress() != null ? bytesToHex(getAddress()) : "null") +
                    ", statusCodeBCD=0x" + String.format("%02X", statusCodeBCD) +
                    ", waterPrice1=" + bytesToHex(getWaterPrice1()) + "(" + getWaterPrice1Value() + "厘)" +
                    ", waterPrice2=" + bytesToHex(getWaterPrice2()) + "(" + getWaterPrice2Value() + "厘)" +
                    ", waterPrice3=" + bytesToHex(getWaterPrice3()) + "(" + getWaterPrice3Value() + "厘)" +
                    ", tieredPrice1=" + bytesToHex(getTieredPrice1()) + "(" + getTieredPrice1Value() + "厘)" +
                    ", tieredPrice2=" + bytesToHex(getTieredPrice2()) + "(" + getTieredPrice2Value() + "厘)" +
                    ", tieredPrice3=" + bytesToHex(getTieredPrice3()) + "(" + getTieredPrice3Value() + "厘)" +
                    '}';
        }
    }

    /**
     * 判断是否为价格查询报文（通过用户数据长度判断）
     * @return true表示是价格查询，false表示是充值报文
     */
    public static boolean isPriceQuery(byte[] userData) {
        return userData == null || userData.length == 0;
    }

    /**
     * 将字节数组转换为十六进制字符串
     */
    protected static String bytesToHex(byte[] bytes) {
        if (bytes == null) return "null";
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < bytes.length; i++) {
            if (i > 0) sb.append(" ");
            sb.append(String.format("%02X", bytes[i] & 0xFF));
        }
        sb.append("]");
        return sb.toString();
    }
}
